package it.localhost.deepthought.one.activity;

import it.localhost.deepthought.one.R;
import it.localhost.deepthought.one.common.AdManager;
import it.localhost.deepthought.one.fragment.ImageDialogFragment;
import it.localhost.deepthought.one.service.ArtificialIntelligence;

import java.nio.ByteBuffer;
import java.util.ArrayList;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.DragEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;
import android.widget.ToggleButton;

import com.google.android.gms.ads.AdView;
import com.google.android.gms.games.Games;
import com.google.android.gms.games.snapshot.SnapshotMetadataChange;

public class MainActivity extends AbstractActivity {// NO_UCD
	private static final String CLOSE1 = "]";
	private static final String OPEN1 = "[";
	private static final String CLOSE2 = ")";
	private static final String OPEN2 = "(";
	private static final String TO = ">";
	private static final String EQ = " = ";
	private static final String AI = "AI";
	private static final String USER = "User";
	private static final String COMPUTING_POWER = "% Computing Power";
	private static final String TURN = "1Turn";
	private static final String SEL_LEVEL = "selLevel";
	private static final String PIE_ROLE = "pieRole";
	private static final String CUORI = "Cuori";
	private static final String PIQUE = "Pique";
	private static final String GAME_WIN = "GAME_WIN";
	private static final String GAME_LOSE = "GAME_LOSE";
	private static final String TRANSLATION_X = "translationX";
	private static final String ROTATION_Y = "rotationY";
	private static final int[] CARD = new int[] { R.drawable.card1, R.drawable.card2, R.drawable.card3, R.drawable.card4, R.drawable.card5, R.drawable.card6, R.drawable.card7, R.drawable.card8 };
	private static final String AUDIO = "audio";
	private SharedPreferences sp;
	private LinearLayout cardLayout;
	private boolean aiPicche, aiTurn, userPieRole, starting;
	private int selLevel, turn;
	private Button button;
	private ImageView aiSemeImg, userSemeImg, userIconImg, aiIconImg;
	private MediaPlayer mp;
	private StringBuilder log;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setVolumeControlStream(AudioManager.STREAM_MUSIC);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		setContentView(R.layout.main);
		starting = true;
		sp = PreferenceManager.getDefaultSharedPreferences(this);
		mp = MediaPlayer.create(this, R.raw.soundtrack);
		mp.setLooping(true);
		cardLayout = (LinearLayout) findViewById(R.id.linear_layout);
		button = (Button) findViewById(R.id.button);
		aiSemeImg = (ImageView) findViewById(R.id.aiSeme);
		userSemeImg = (ImageView) findViewById(R.id.userSeme);
		userIconImg = (ImageView) findViewById(R.id.userIcon);
		aiIconImg = (ImageView) findViewById(R.id.aiIcon);
		log = new StringBuilder();
		aiPicche = sp.getInt(MenuActivity.SEME, 0) == 0;
		aiTurn = sp.getInt(MenuActivity.TURNO, 0) == 0;
		log.append(OPEN1 + AI + EQ + (aiPicche ? PIQUE : CUORI) + CLOSE1);
		log.append(OPEN1 + TURN + EQ + (aiTurn ? USER : AI) + CLOSE1);
		for (int i = 0; i < 8; i++) {
			cardLayout.getChildAt(i).setTag(i + 1);
			cardLayout.getChildAt(i).setOnTouchListener(new CardOnTouchListener());
			cardLayout.getChildAt(i).setOnDragListener(new CardOnDragListener());
		}
		ObjectAnimator rewardAnimm = ObjectAnimator.ofFloat(findViewById(R.id.reward), ROTATION_Y, 30, -30);
		rewardAnimm.setRepeatCount(ObjectAnimator.INFINITE);
		rewardAnimm.setRepeatMode(ObjectAnimator.REVERSE);
		rewardAnimm.start();
		button.setOnClickListener(new UserPieRoleListener());
		turn = 0;
		setSeme();
		new AdManager().load(this, ((AdView) findViewById(R.id.adView)), true);
	}

	@Override
	public void onResume() {
		super.onResume();
		if (mp != null && sp.getBoolean(AUDIO, true))
			mp.start();
	}

	@Override
	public void onStop() {
		super.onStop();
		if (mp != null)
			mp.pause();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		if (mp != null)
			mp.release();
	}

	@Override
	public void onSignIn() {
		if (starting) {
			selLevel = getIntent().getIntExtra(MenuActivity.SELECTED_LEV, maxLevel);
			log.append(OPEN1 + SEL_LEVEL + EQ + selLevel + CLOSE1);
			setTitle(selLevel + COMPUTING_POWER);
			((ProgressBar) findViewById(R.id.levelProgressBar)).setProgress(selLevel);
			ArrayList<Animator> al = new ArrayList<Animator>(8);
			for (int i = 0; i < 8; i++) {
				final View card = cardLayout.getChildAt(i);
				int start = card.getMeasuredWidth() * (i % 2 == 0 ? i + 1 : 8 - i + 1);
				ObjectAnimator oa = ObjectAnimator.ofFloat(card, TRANSLATION_X, i % 2 == 0 ? -start : start, 0);
				oa.addListener(new AnimatorListenerAdapter() {
					@Override
					public void onAnimationStart(Animator animation) {
						card.setVisibility(View.VISIBLE);
					}
				});
				al.add(oa);
			}
			ObjectAnimator oa;
			oa = ObjectAnimator.ofFloat(aiSemeImg, TRANSLATION_X, -aiSemeImg.getMeasuredWidth() * 2, 0);
			oa.addListener(new AnimatorListenerAdapter() {
				@Override
				public void onAnimationStart(Animator animation) {
					aiSemeImg.setVisibility(View.VISIBLE);
				}
			});
			al.add(oa);
			oa = ObjectAnimator.ofFloat(userSemeImg, TRANSLATION_X, userSemeImg.getMeasuredWidth() * 2, 0);
			oa.addListener(new AnimatorListenerAdapter() {
				@Override
				public void onAnimationStart(Animator animation) {
					userSemeImg.setVisibility(View.VISIBLE);
				}
			});
			al.add(oa);
			oa = ObjectAnimator.ofFloat(aiIconImg, TRANSLATION_X, -aiIconImg.getMeasuredWidth(), 0);
			oa.addListener(new AnimatorListenerAdapter() {
				@Override
				public void onAnimationStart(Animator animation) {
					aiIconImg.setVisibility(View.VISIBLE);
				}
			});
			al.add(oa);
			oa = ObjectAnimator.ofFloat(userIconImg, TRANSLATION_X, userIconImg.getMeasuredWidth(), 0);
			oa.addListener(new AnimatorListenerAdapter() {
				@Override
				public void onAnimationStart(Animator animation) {
					userIconImg.setVisibility(View.VISIBLE);
				}
			});
			al.add(oa);
			AnimatorSet as = new AnimatorSet();
			as.playSequentially(al);
			as.addListener(new AnimatorListenerAdapter() {
				@Override
				public void onAnimationEnd(final Animator animation) {
					nextTurn();
				}
			});
			as.start();
			starting = false;
		}
	}

	@Override
	public void onSignOut() {
		setResult(RESULT_CANCELED);
		finish();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main_option, menu);
		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		menu.findItem(R.id.audio).setIcon(sp.getBoolean(AUDIO, true) ? R.drawable.ic_volume_high_white_36dp : R.drawable.ic_volume_off_white_36dp);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
			case R.id.audio:
				if (mp.isPlaying()) {
					mp.pause();
					sp.edit().putBoolean(AUDIO, false).commit();
				} else {
					mp.start();
					sp.edit().putBoolean(AUDIO, true).commit();
				}
				item.setIcon(mp.isPlaying() ? R.drawable.ic_volume_high_white_36dp : R.drawable.ic_volume_off_white_36dp);
				item.setTitle(mp.isPlaying() ? R.string.disable_audio : R.string.enable_audio);
			default:
				return super.onOptionsItemSelected(item);
		}
	}

	private void setupCards() {
		for (int i = 0; i < 8; i++)
			cardLayout.getChildAt(i).setEnabled(false);
		if (!aiTurn)
			for (int i = 0; i < 8; i++) {
				int it = (Integer) cardLayout.getChildAt(i).getTag();
				for (int j = 0; j < 8; j++) {
					int jt = (Integer) cardLayout.getChildAt(j).getTag();
					if ((i - j) * (it - jt) > 0)
						cardLayout.getChildAt(i).setEnabled(true);
				}
			}
	}

	private void swapCards(final ToggleButton sx, final ToggleButton dx, boolean isUser) {
		sx.setChecked(true);
		dx.setChecked(true);
		for (int i = 0; i < 8; i++)
			cardLayout.getChildAt(i).setEnabled(false);
		final int valueSx = Integer.valueOf((Integer) sx.getTag());
		final int valueDx = Integer.valueOf((Integer) dx.getTag());
		log.append(OPEN1 + (isUser ? USER : AI) + OPEN2 + valueSx + TO + valueDx + CLOSE2 + CLOSE1);
		final AnimatorSet firstAS = new AnimatorSet();
		final AnimatorSet lastAS = new AnimatorSet();
		final AnimatorSet as = new AnimatorSet();
		sx.setTag(valueDx);
		dx.setTag(valueSx);
		firstAS.playTogether(ObjectAnimator.ofFloat(sx, ROTATION_Y, 0, 90), ObjectAnimator.ofFloat(dx, ROTATION_Y, 0, 90));
		lastAS.playTogether(ObjectAnimator.ofFloat(sx, ROTATION_Y, 90, 0), ObjectAnimator.ofFloat(dx, ROTATION_Y, 90, 0));
		as.playSequentially(firstAS, lastAS);
		firstAS.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationEnd(final Animator animation) {
				sx.setBackgroundResource(CARD[valueDx - 1]);
				dx.setBackgroundResource(CARD[valueSx - 1]);
			}
		});
		lastAS.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationEnd(final Animator animation) {
				sx.setChecked(false);
				dx.setChecked(false);
				endTurn();
			}
		});
		as.start();
	}

	private void pieRole() {
		log.append(OPEN1 + PIE_ROLE + CLOSE1);
		Toast.makeText(this, R.string.pieRole, Toast.LENGTH_SHORT).show();
		final AnimatorSet firstAS = new AnimatorSet();
		final AnimatorSet lastAS = new AnimatorSet();
		final AnimatorSet as = new AnimatorSet();
		firstAS.playTogether(ObjectAnimator.ofFloat(aiSemeImg, ROTATION_Y, 0, 90), ObjectAnimator.ofFloat(userSemeImg, ROTATION_Y, 0, 90));
		lastAS.playTogether(ObjectAnimator.ofFloat(aiSemeImg, ROTATION_Y, 90, 0), ObjectAnimator.ofFloat(userSemeImg, ROTATION_Y, 90, 0));
		as.playSequentially(firstAS, lastAS);
		firstAS.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationEnd(final Animator animation) {
				aiPicche = !aiPicche;
				setSeme();
			}
		});
		lastAS.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationEnd(final Animator animation) {
				endTurn();
			}
		});
		as.start();
	}

	private void endTurn() {
		StringBuilder inputSb = new StringBuilder();
		for (int i = 0; i < 8; i++)
			inputSb.append(cardLayout.getChildAt(i).getTag());
		int win = ArtificialIntelligence.whoWin(inputSb.toString());
		if (win != 2) {
			button.setVisibility(View.VISIBLE);
			button.setOnClickListener(new EndGameListener());
			for (int i = 0; i < 8; i++)
				((ToggleButton) cardLayout.getChildAt(i)).setChecked((Integer) cardLayout.getChildAt(i).getTag() % 2 == 0 ? win == 1 : win == -1);
		}
		if (win == 0) {
			Games.Achievements.increment(googleApiClient, getString(R.string.achievement_perfect_symmetry), 1);
			speak(R.string.draw);
			new ImageDialogFragment().show(this, R.string.draw, R.drawable.humanlose, false);
			button.setText(R.string.again);
		} else if ((win == 1 && !aiPicche) || (win == -1 && aiPicche)) {
			Games.Achievements.increment(googleApiClient, getString(R.string.achievement_die_hard), 1);
			speak(R.string.lose);
			new ImageDialogFragment().show(this, R.string.lose, R.drawable.humanlose, false);
			button.setText(R.string.again);
			sendEvent(GAME_LOSE, Integer.toString(selLevel), log.toString());
		} else if ((win == 1 && aiPicche) || (win == -1 && !aiPicche)) {
			if (selLevel == 0)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_ready_to_lose));
			else if (selLevel == 10)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_10_is_a_great_achievement_d));
			else if (selLevel == 25)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_first_quarter_completed));
			else if (selLevel == 50)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_welcome_in_the_middle));
			else if (selLevel == 75)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_youre_better_than_my_75_of_my_computing_power));
			else if (selLevel == 90)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_hell_mode_activated));
			else if (selLevel == 99)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_completed_last_level_you_can_do));
			else if (selLevel == 100)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_save_humanity_and_the_planet));
			if (userPieRole && selLevel >= 50)
				Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_pie_victory));
			if (selLevel == 99)
				Games.Achievements.increment(googleApiClient, getString(R.string.achievement_level_99__99_times), 1);
			Games.Leaderboards.submitScore(googleApiClient, getString(R.string.leaderboard_top_rescuers_of_humanity), selLevel);
			sendEvent(GAME_WIN, Integer.toString(selLevel), log.toString());
			speak(R.string.win);
			new ImageDialogFragment().show(this, R.string.win, R.drawable.humanwin, false);
			button.setText(R.string.next);
			selLevel++;
			if (selLevel > maxLevel) {
				snapshot.getSnapshotContents().writeBytes(ByteBuffer.allocate(4).putInt(selLevel).array());
				Games.Snapshots.commitAndClose(googleApiClient, snapshot, SnapshotMetadataChange.EMPTY_CHANGE);
			}
		} else
			nextTurn();
	}

	private void nextTurn() {
		turn++;
		aiTurn = !aiTurn;
		aiIconImg.setEnabled(aiTurn);
		userIconImg.setEnabled(!aiTurn);
		StringBuilder inputSb = new StringBuilder();
		for (int i = 0; i < 8; i++) {
			inputSb.append(cardLayout.getChildAt(i).getTag());
			setupCards();
		}
		if (aiTurn && turn == 2 && ArtificialIntelligence.noMoves(this, inputSb.toString(), aiPicche, selLevel)) {
			pieRole();
			Games.Achievements.unlock(googleApiClient, getString(R.string.achievement_binary_pie));
		} else if (aiTurn) {
			int[] move = ArtificialIntelligence.getMove(this, inputSb.toString(), aiPicche, selLevel);
			swapCards((ToggleButton) cardLayout.getChildAt(move[0]), (ToggleButton) cardLayout.getChildAt(move[1]), false);
		} else if (!aiTurn && turn == 2)
			button.setVisibility(View.VISIBLE);
	}

	private void setSeme() {
		aiSemeImg.setImageResource(aiPicche ? R.drawable.piccheb : R.drawable.cuoreb);
		userSemeImg.setImageResource(aiPicche ? R.drawable.cuoreb : R.drawable.piccheb);
	}

	private final class EndGameListener implements View.OnClickListener {
		@Override
		public void onClick(View paramView) {
			Intent intent = new Intent(MainActivity.this, MainActivity.class);
			intent.putExtra(MenuActivity.SELECTED_LEV, selLevel);
			startActivity(intent);
			finish();
		}
	}

	private final class UserPieRoleListener implements View.OnClickListener {
		@Override
		public void onClick(View paramView) {
			for (int i = 0; i < 8; i++)
				cardLayout.getChildAt(i).setEnabled(false);
			button.setVisibility(View.INVISIBLE);
			userPieRole = true;
			pieRole();
		}
	}

	private final class CardOnTouchListener implements OnTouchListener {
		public boolean onTouch(View view, MotionEvent motionEvent) {
			if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
				view.setEnabled(false);
				boolean found = false;
				int value = (Integer) view.getTag();
				for (int i = 0; i < 8; i++) {
					int ivalue = (Integer) cardLayout.getChildAt(i).getTag();
					if (value == ivalue)
						found = true;
					else
						cardLayout.getChildAt(i).setEnabled(found == ivalue > value);
				}
				view.startDrag(null, new DragShadowBuilder(view), view, 0);
				button.setVisibility(View.INVISIBLE);
				return true;
			} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
				view.performClick();
				return false;
			} else
				return false;
		}
	}

	private final class CardOnDragListener implements OnDragListener {
		@Override
		public boolean onDrag(View woman, DragEvent event) {
			switch (event.getAction()) {
				case DragEvent.ACTION_DRAG_ENTERED:
					((ToggleButton) woman).setChecked(true);
					return true;
				case DragEvent.ACTION_DRAG_EXITED:
					((ToggleButton) woman).setChecked(false);
					return true;
				case DragEvent.ACTION_DROP:
					swapCards((ToggleButton) woman, (ToggleButton) event.getLocalState(), true);
					return true;
				case DragEvent.ACTION_DRAG_ENDED:
					setupCards();
					if (!aiTurn && turn == 2)
						button.setVisibility(View.VISIBLE);
					return false;
				default:
					return true;
			}
		}
	}
}